﻿
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using HBase.cache;

namespace HBase
{
    public abstract class ZtTask :ITask {
        public String p;
        public TaskStat getStat() {
            return stat;
        }

        public static MyNewDict<string ,object> lockDict = new MyNewDict<string, object>();

        public TaskStat stat = new TaskStat();
        protected String className;

        private Task jobTask;
        protected int time = 100;
        protected bool exceptionSleep = true;
        protected int oneTimeSleep = 0;
        private int extralSleep = 2000;
        public bool runed = false;
        public ZtTask() {
            className = this.GetType().Name;
            stat.className = className;
        }
        protected virtual bool init() {
            return true;
        }
        public void start() {
            try {
                if( runed ) {
                    console("已经启动");
                }
                if( !init() ) {
                    console("初始化异常");
                    return;
                }
                runed = false;
                jobTask = Task.Factory.StartNew(() => { doAction(); } ,TaskCreationOptions.LongRunning);
      
            } catch( Exception e ) {

                LoggerCommon.errorFile(className + "初始化异常" ,e);
            }
        }
        protected virtual bool onlyOneTimeAsync() {
            return true;
        }
        protected virtual long oneMaxTime() {
            return 2000 + time + oneTimeSleep;
        }
 
        private void doAction() {
            do {
                try {

                   
                    bool res = work();
                    Thread.Sleep(time + oneTimeSleep);
                    oneTimeSleep = 0;
                    if( res ) {
                        extralSleep = 2000;
                    } else {
                        fileAll("延期执行{0}s" ,extralSleep / 1000);
                        exceptionSleeps();
                    }

                } catch( Exception ex ) {
                    String show = string.Format("{0} sleep {1}s :{2}" ,className ,extralSleep / 1000 ,ex.Message);
                    LoggerCommon.error(show ,ex);
                    exceptionSleeps();
                }
            } while( true );
        }
        /// <summary>
        ///
        /// </summary>
        public bool work() {
            lock( stat ) {
                bool res = false;
                if( !runed ) {
                    runed = onlyOneTimeAsync();
                }
                stat.time = this.time;
        
                long beginTime = DateTime.Now.Ticks;
                if( isStandAlone()) {
                     res = excute(); 
                } else {
                    ITask t = TaskPool.getIniting();
                    if (t == null  ) {
                        res = excute();
                    }else {
                        consoleOnly(t.GetType().Name + "初始化中");
                    }
                  
                }
                afterExcute();
                analysis(beginTime);
                return res;
            }
        }
        public virtual void afterExcute() { }
        void analysis(long beginTime) {
            var n = DateTime.Now;
            long lastTime = (n.Ticks - beginTime);
            long d = beginTime - HUtil.randSeek;
            d = d > 0 ? d >> 40 : 0;
            stat.worklastTime = lastTime;
            if( lastTime > oneMaxTime()*10000 ) {
                fileAll("线程执行时间过长" + lastTime);
            }
            stat.workAllTime += lastTime;
            stat.workCount++;
            if( lastTime > stat.maxTime ) {
                stat.maxTime = lastTime;
            }
            if( lastTime < stat.minTime || stat.minTime == 0 ) {
                stat.minTime = lastTime;
            }
            oneTimeSleep = oneTimeSleep == 0 ? ( int ) d : oneTimeSleep;

        }
        protected void exceptionSleeps() {
            stat.exceptionCount++;
            Thread.Sleep(extralSleep);
            extralSleep *= 2;
            if( extralSleep > 120000 ) {
                extralSleep = 120000;
            }
        }
        abstract public bool excute();
        public void fileAll(String format ,params object[] p) {
            LoggerCommon.fileAll(formatStr(  format,   p));
        }

        String formatStr(String format, params object[] p) {
            if (p.Length > 0) {
                String[] pp = new string[p.Length];
                for (int i = 0; i < pp.Length; i++) {
                    pp[i] = "[" + p[i].ToString() + "]";
                }
                format = String.Format(format, p);
            }
            return className + "->" + format;
        }
        public void console(String format ,params object[] p) {
            LoggerCommon.consol(formatStr(format, p));
        }
        public void consoleOnly(String format ,params object[] p) {
           
            LoggerCommon.consoleOnly(formatStr(format, p));
        }
        public virtual  bool isStandAlone() {
            return false;
        }
        public bool isRuned() {
            return runed;
        }
    }
}
